package com.oauth.service.impl;

import com.oauth.config.OauthConfig;
import com.oauth.error.OauthError;
import com.oauth.exception.OAuthErrorException;
import com.oauth.mapper.OpenTokenMapper;
import com.oauth.model.OpenResourceAuth;
import com.oauth.model.OpenToken;
import com.oauth.service.*;
import com.oauth.util.AuthUtil;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.types.GrantType;
import org.apache.oltu.oauth2.common.message.types.ResponseType;
import org.apache.oltu.oauth2.common.message.types.TokenType;
import org.apache.oltu.oauth2.common.token.BasicOAuthToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 * 令牌服务
 * Created by yangjianbo on 2016/9/29.
 */
@Service
public class OauthTokenServiceImpl implements OauthTokenService {

    @Autowired
    private OpenTokenService openTokenService;

    @Autowired
    private OpenClientService openClientService;

    @Autowired
    private OpenResourceAuthService openResourceAuthService;

    @Autowired
    private OpenResourceService openResourceService;

    @Override
    public BasicOAuthToken tokenByCode(String client_id, String client_secret, String code, String redirec_uri, String scope) throws OAuthProblemException, OAuthSystemException {

        if(!openClientService.isExisted(client_id)){
            throw  OAuthErrorException.error(OauthError.errorModel_client_not_exited);
        }else if(!openClientService.isUsed(client_id)){
            throw  OAuthErrorException.error(OauthError.errorModel_client_not_useed);
        }else if(!openClientService.isMatched(client_id,client_secret)){
            throw  OAuthErrorException.error(OauthError.errorModel_clientSecret_not_correct);
        }else {
             OpenToken token=openTokenService.select(client_id,code);
             if(token==null){
                 throw OAuthProblemException.error("client_id,code不匹配");
             }else if(!token.getRedirectUri().equals(redirec_uri)){
                 throw OAuthProblemException.error("回调地址不匹配");
             }else if(false){
                 //判断权限是否匹配
                 throw OAuthProblemException.error("申请保护资源超出范围");
             }else if(!token.getStatus().equals(1)){
                 throw OAuthProblemException.error("code已经失效");
             }
             else {
                     BasicOAuthToken basicOAuthToken=
                             new BasicOAuthToken(AuthUtil.getMd5Token(), TokenType.BEARER.toString(),
                                     OauthConfig.ACCESS_TOKEN_VALIDITY_SECONDS+0l,AuthUtil.getMd5RefreshToken(),scope);

                 token.setGrantType(GrantType.AUTHORIZATION_CODE.toString());
                 token.setAccessToken(basicOAuthToken.getAccessToken());
                 token.setClientSecret(client_secret);
                 token.setRefreshToken(basicOAuthToken.getRefreshToken());
                 Date date1=new Date(System.currentTimeMillis()+OauthConfig.ACCESS_TOKEN_VALIDITY_SECONDS*1000);
                 Date date2=new Date(System.currentTimeMillis()+OauthConfig.REFRESH_TOKEN_VALIDITY_SECONDS*1000);
                 token.setExpiresIn(date1);
                 token.setRefreshExpiresIn(date2);
                 token.setStatus(2);//只能刷新令牌
                 openTokenService.update(token);
                 return basicOAuthToken;
             }
        }
    }

    @Override
    public BasicOAuthToken tokenByClient(String client_id, String client_secret,String scope) throws OAuthProblemException, OAuthSystemException {
        if(!openClientService.isExisted(client_id)){
            throw  OAuthErrorException.error(OauthError.errorModel_client_not_exited);
        }else if(!openClientService.isUsed(client_id)){
            throw  OAuthErrorException.error(OauthError.errorModel_client_not_useed);
        }else if(!openClientService.isMatched(client_id,client_secret)){
            throw  OAuthErrorException.error(OauthError.errorModel_clientSecret_not_correct);
        }else if(false){
            throw  OAuthErrorException.error(OauthError.errorModel_scope_out);
        }
        else {
            OpenToken openToken=new OpenToken();
            openToken.setClientId(client_id);
            openToken.setClientSecret(client_secret);
            openToken.setScope(scope);
            openToken.setAccessToken(AuthUtil.getMd5Token());
            Date date1=new Date(System.currentTimeMillis()+OauthConfig.ACCESS_TOKEN_VALIDITY_SECONDS*1000);
            openToken.setExpiresIn(date1);
            openToken.setStatus(3);
            openTokenService.insert(openToken);
            BasicOAuthToken basicOAuthToken=new BasicOAuthToken(
                    openToken.getAccessToken(),TokenType.BEARER.toString(),OauthConfig.ACCESS_TOKEN_VALIDITY_SECONDS+0l,openToken.getScope());
            return basicOAuthToken;
        }
    }

    @Override
    public BasicOAuthToken tokenByPassword(String client_id, String client_secret, String username, String password, String scope) throws OAuthProblemException, OAuthSystemException {
        if(!openClientService.isExisted(client_id)){
            throw  OAuthErrorException.error(OauthError.errorModel_client_not_exited);
        }else if(!openClientService.isUsed(client_id)){
            throw  OAuthErrorException.error(OauthError.errorModel_client_not_useed);
        }else if(!openClientService.isMatched(client_id,client_secret)){
            throw  OAuthErrorException.error(OauthError.errorModel_clientSecret_not_correct);
        }else if(false){
            throw OAuthProblemException.error("用户名密码不正确");
        }else if(false){
            throw  OAuthErrorException.error(OauthError.errorModel_scope_out);
        }
        else {
            OpenToken openToken=new OpenToken();
            openToken.setClientId(client_id);
            openToken.setClientSecret(client_secret);
            openToken.setScope(scope);
            openToken.setAccessToken(AuthUtil.getMd5Token());
            Date date1=new Date(System.currentTimeMillis()+OauthConfig.ACCESS_TOKEN_VALIDITY_SECONDS*1000);
            openToken.setExpiresIn(date1);
            openToken.setStatus(5);
            openTokenService.insert(openToken);
            BasicOAuthToken basicOAuthToken=new BasicOAuthToken(
                    openToken.getAccessToken(),TokenType.BEARER.toString(),OauthConfig.ACCESS_TOKEN_VALIDITY_SECONDS+0l,openToken.getScope());
            return basicOAuthToken;
        }
    }

    @Override
    public BasicOAuthToken tokenByRefresh(String refresh_token, String scope) throws OAuthProblemException, OAuthSystemException {

        OpenToken openToken=openTokenService.select(refresh_token);
        if(openToken==null){
            throw  OAuthErrorException.error(OauthError.errorModel_refrehToken_Illegal);
        }else if(openToken.getRefreshExpiresIn().before(new Date())){
            throw  OAuthErrorException.error(OauthError.errorModel_refrehToken_Invalid);
        }else if(false){
            throw  OAuthErrorException.error(OauthError.errorModel_scope_out);
        }else{
            openToken.setAccessToken(AuthUtil.getMd5Token());
            Date date1=new Date(System.currentTimeMillis()+OauthConfig.ACCESS_TOKEN_VALIDITY_SECONDS*1000);
            openToken.setExpiresIn(date1);
            openTokenService.update(openToken);
            BasicOAuthToken basicOAuthToken=
                    new BasicOAuthToken(openToken.getAccessToken(), TokenType.BEARER.toString(),
                            OauthConfig.ACCESS_TOKEN_VALIDITY_SECONDS+0l,openToken.getRefreshToken(),scope);
            return basicOAuthToken;
        }
    }

    @Override
    public Boolean isEnable(String token, String resoure) throws OAuthProblemException {
        OpenToken stoken=openTokenService.selectByAccessToken(token);
        if(stoken==null){
            throw  OAuthErrorException.error(OauthError.errorModel_accessToken_Invalid);

        }else if(new Date().after(stoken.getExpiresIn())){
            throw  OAuthErrorException.error(OauthError.errorModel_accessToken_expired);

        }else if(openResourceService.isEnable(resoure)){
            //验证访问该资源是否有权限
            throw  OAuthErrorException.error(OauthError.errorModel_resource_not_enable);

        }else {
            OpenResourceAuth openResourceAuth= openResourceAuthService.select(stoken.getClientId(),resoure);
            if(openResourceAuth==null){
                return false;
            }else {
                return true;
            }
            //写入日志
        }
    }
}
